using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace Engine.IO
{
    public class FileTools
    {
        #region MEMBERS
        private Business.Interfaces.IMatchFile FileComparer;
        Engine.Business.Abstract.ProcessType TypeOfProcess;
        IO.CRC32 CRCCalculator = null;
        private  Engine.Business.Interfaces.IProgressHandler NotifyProgress;

        static private System.Collections.Generic.Dictionary<string, long> CRC32cache
            = new System.Collections.Generic.Dictionary<string, long>();//static cache for files CRC32

        #endregion

        #region CTOR

        public FileTools(Business.Interfaces.IMatchFile fc, 
            Engine.Business.Abstract.ProcessType pt,
            Engine.Business.Interfaces.IProgressHandler ph)
        {
            FileComparer = fc;
            CRCCalculator = new IO.CRC32();
            TypeOfProcess = pt;
            NotifyProgress = ph;
        }
        #endregion

        #region PUBLIC

        public long GetFileCRC32(System.IO.FileInfo fi)
        {
            NotifyProgress.WriteToOutput("GetFileCRC32 begins for " + fi.FullName, Engine.Business.LogPriority.DEBUG);

            long crc = 0;

            if(DataSchema.Settings.SettingsMgr.UseCRC32Chache && CRC32cache.ContainsKey(fi.FullName))
            {
                NotifyProgress.WriteToOutput("Got CRC32 from cache for " + fi.FullName, Engine.Business.LogPriority.DEBUG);
                crc = CRC32cache[fi.FullName];
            }
            else
            {
                FileStream fs = fi.OpenRead();
                crc = this.CRCCalculator.CRC(fs);
                fs.Close();
                if(DataSchema.Settings.SettingsMgr.UseCRC32Chache)
                    CRC32cache.Add(fi.FullName, crc);
            }
            NotifyProgress.WriteToOutput("GetFileCRC32 ends for " + fi.FullName, Engine.Business.LogPriority.DEBUG);
            return crc;
        }

        public bool VerifyFile(System.IO.FileInfo fi, Engine.Business.Abstract.CollectionItem c)
        {
            if (fi.Exists)
            {
                //first compare size
                if (c.Size == fi.Length)
                {
                    if (TypeOfProcess == Engine.Business.Abstract.ProcessType.Hunt)
                    {
                        long crc = 0;

                        if(DataSchema.Settings.SettingsMgr.UseCRC32Chache && CRC32cache.ContainsKey(fi.FullName))
                            crc = CRC32cache[fi.FullName];
                        else
                        {
                            FileStream fs = fi.OpenRead();
                            crc = this.CRCCalculator.CRC(fs);
                            fs.Close();
                            if(DataSchema.Settings.SettingsMgr.UseCRC32Chache)
                                CRC32cache.Add(fi.FullName, crc);
                        }
                        
                        if (c.CRC32 == crc)
                            return true;
                    }
                    else if (TypeOfProcess == Engine.Business.Abstract.ProcessType.Verify)
                        return true;
                }
            }
            return false;
        }

        public int Search(string[] paths, ref bool cont)
        {
            int i = 0;
            foreach(string p in paths)
            {
                FileSystemEnumerator fe = new FileSystemEnumerator(p, "*.*", true);

                foreach(FileInfo fi in fe.Matches())
                {
                    if (cont == false)
                        break;

                    Business.Abstract.CollectionItem c = FileComparer.Match(fi);
                    if(c != null)//item found
                    {
                        if(FileComparer.Process(fi,c))
                            ++i;
                    }
                }
            }
            return i;
        }
    
        public int GetFilesCount(string[] paths)
        {
            int i = 0;
            foreach(string p in paths)
            {
                FileSystemEnumerator fe = new FileSystemEnumerator(p, "*.*", true);

                foreach(FileInfo fi in fe.Matches())
                {
                    ++i;
                }
            }
            return i;
        }
        #endregion

        #region STATIC

    	public static string GetSize(double size)
	    {
		    double s = size;

		    string[] format = new string[] {"{0} bytes", "{0} KB","{0} MB", "{0} GB", "{0} TB", "{0} PB", "{0} EB"};

		    int i = 0;

		    while (i < format.Length && s >= 1024) {

			    s = (double) (100 * s / 1024) / 100.0;
			    i++;
		    }
            s = Math.Round(s, 2);
		    return string.Format(format[i],s);
	    }


        static public void DeleteFile(string path)
        { 
            FileInfo f = new FileInfo(path);
            if(f.Exists)
                f.Delete();
        }

        static public bool FileExist(string path)
        {
            FileInfo f = new FileInfo(path);
            return (f.Exists);
        }

        static public bool OpenFile(string imgpath, string arg, bool skip)
        {
            if(skip == false && FileExist(imgpath) == false)
            {
                return false;
            }
            ProcessStartInfo pInfo = new ProcessStartInfo();
            pInfo.FileName = imgpath;
            pInfo.Arguments = arg;
            pInfo.UseShellExecute = true;
            Process p = Process.Start(pInfo);
            return true;
        }

        #endregion
    }
}
